package main

import "fmt"

// Node represents a node in the doubly linked list.
type Node struct {
	data int
	prev *Node
	next *Node
}

// DoublyLinkedList represents the doubly linked list.
type DoublyLinkedList struct {
	head *Node
	tail *Node
}

// Insert appends a new node with the given data to the end of the list.
func (dll *DoublyLinkedList) Insert(data int) {
	newNode := &Node{data: data, prev: nil, next: nil}

	if dll.head == nil {
		dll.head = newNode
		dll.tail = newNode
	} else {
		newNode.prev = dll.tail
		dll.tail.next = newNode
		dll.tail = newNode
	}
}

// Display prints the data of all nodes in the list from head to tail.
func (dll *DoublyLinkedList) Display() {
	if dll.head == nil {
		fmt.Println("DoublyLinkedList is empty")
		return
	}

	current := dll.head
	for current != nil {
		fmt.Printf("%d ", current.data)
		current = current.next
	}
	fmt.Println()
}

// Delete removes the first node with the specified data from the list.
func (dll *DoublyLinkedList) Delete(data int) {
	if dll.head == nil {
		return
	}

	current := dll.head
	for current != nil {
		if current.data == data {
			// If the node to be deleted is the head node
			if current == dll.head {
				dll.head = current.next
				if dll.head != nil {
					dll.head.prev = nil
				} else {
					dll.tail = nil
				}
			} else if current == dll.tail {
				// If the node to be deleted is the tail node
				dll.tail = current.prev
				dll.tail.next = nil
			} else {
				// If the node to be deleted is in the middle
				current.prev.next = current.next
				current.next.prev = current.prev
			}
			return
		}
		current = current.next
	}
}

func main() {
	dll := DoublyLinkedList{}

	dll.Insert(10)
	dll.Insert(20)
	dll.Insert(30)
	dll.Insert(40)

	fmt.Println("Initial DoublyLinkedList:")
	dll.Display()

	dll.Delete(20)
	dll.Delete(30)

	fmt.Println("DoublyLinkedList after deletion:")
	dll.Display()
}
